package Exception;/*
 *
 * @author 陈粒
 * @version 创建时间：2021/7/7 19:31
 */

/**
 * 注意1：异常的顶级父类为Throwable，不是Exception
 * 注意2：异常处理只有两种方式: catch 和 throws,所以必须二选一
 * 1.Java异常机制用到的几个关键字：try、catch、finally、throw、throws。
 * 2.  三种类型的异常：
 * （1）检查性异常(编译错误)：最具代表的检查性异常是用户错误或问题引起的异常，这是程序员无法预见的。例如要打开一个不存在文件时，一个异常就发生了，这些异常在编译时不能被简单地忽略。
 * （2）运行时异常(运行时错误)： 运行时异常是可能被程序员避免的异常。与检查性异常相反，运行时异常可以在编译时被忽略。
 * （3）错误： 错误不是异常，而是脱离程序员控制的问题。错误在代码中通常被忽略。例如，当栈溢出时，一个错误就发生了，它们在编译也检查不到的。
 *  常见的运行时异常：空指针异常(NullPointerException)、除零异常(ArithmeticException)、数组越界异常(ArrayIndexOutOfBoundsException)等;
 *  常见的检查性异常：输入输出异常(IOException)、文件不存在异常(FileNotFoundException)、SQL语句异常(SQLException)等。
 * 一、Java异常的分类：
 * Error：指的是JVM错误，这时的程序并没有执行，无法处理；
 * Exception：指的是程序运行中产生的异常，用户可以使用处理格式处理。
 *二、try、catch、finally
 * 用法：
 * 在方法里
 * 1.try{
 *          （可能会发生异常的的语句块）
 *         }catch (要捕获的异常类型 异常类型对象){
 *         （执行语句）
 *         }finally {
 *         （执行语句）
 *         }
 * 2.try{
 *         （可能会发生异常的的语句块）
 *         }catch (要捕获的异常类型 异常名){
 *         （执行语句）
 *         }
 * 3.try{
 *        （可能会发生异常的的语句块）
 *         }finally {
 *        （执行语句）
 *         }
 * 注意：
 * catch 不能独立于 try 存在。
 * catch里面不能没有内容
 * 在 try/catch 后面添加 finally 块并非强制性要求的。
 * try 代码后不能既没 catch 块也没 finally 块。
 * try里面越少越好。
 * try, catch, finally 块之间不能添加任何代码。
 * finally里面的代码最终一定会执行（除了JVM退出）
 * 如果程序可能存在多个异常，需要多个catch进行捕获。
 * 异常如果是同级关系，catch谁前谁后没有关系
 * 如果异常之间存在上下级关系，上级需要放在后面
 * 重点：当catch捕获不到想要的异常时，再多写个catch(Exception e)用来捕获这个未知异常
 * 三、throw
 *   throw是人为抛出一个异常。
 *   用法：
 *   在方法里
 *   throw new 异常;
 *   如：throw new NumberFormatException();
 * 一般会用于程序出现某种逻辑时程序员主动抛出某种特定类型的异常
 * 注意：执行throw一定抛出了某种异常
 * 四、throws
 * throws是方法可能抛出异常的声明。(用在声明方法时，表示该方法可能要抛出的异常)
 * 这种解决方法不好，抛出异常给main
 * 用法：
 * 在方法名称上
 * [(修饰符)](返回值类型)(方法名)([参数列表])[throws(异常类)]{......}
 *       如：      public void function() throws Exception{......}
 * 当某个方法可能会抛出某种异常时用于throws 声明可能抛出的异常，然后交给上层调用它的方法程序处理。
 * 五、自定义异常类
 * 在 Java 中你可以自定义异常。如果要自定义异常类，则扩展Exception类即可，因此这样的自定义异常都属于检查异常（checked exception）。如果要自定义非检查异常，则扩展自RuntimeException。
 * 按照国际惯例，自定义的异常应该总是包含如下的构造函数：
 * 一个无参构造函数
 * 一个带有String参数的构造函数，并传递给父类的构造函数。
 * 一个带有String参数和Throwable参数，并都传递给父类构造函数
 * 一个带有Throwable 参数的构造函数，并传递给父类的构造函数。
 * 注意：我们要在调用main方法之前解决掉异常，不能把异常留给main方法处理，因为没人解决了
 */
public class Exception1_Test {
    public static void main(String[] args) {
        Exception1 e1 = new Exception1();
        Exception2 e2 = new Exception2();
        Exception3 e3 = new Exception3();
        e1.Test1();//测试try，catch，finally
        e2.Test2();//测试throw
        e3.Test3();//测试throws

    }
}

class Exception1 {//非检查性异常里的运行时异常，ArithmeticException异常

    void Math1() {
        int a = 10 / 0;
    }

    void Test1() {//try，catch，finally
        try {
            Math1();
        } catch (ArithmeticException e) {
            System.out.println("赋值错误");
            String s1 = e.getMessage();//异常对象e调用getMessage()方法，用来获得错误信息，方法返回String类型
            e.printStackTrace();//异常对象e调用printStackTrace()方法，在控制台打印出异常种类，错误信息和出错位置等
            System.out.println(s1);
        } finally {
            System.out.println("try,catch,finally异常处理结束");
        }
    }
}

class Exception2 {
    void Test2() {//throw
        try {
            String s2 = "abc";
            if (s2.equals("abcd") == false) {//equals方法得到是boolean类型的值，用于对比两个变量的值
                throw new NumberFormatException();//如果满足if条件则抛出异常，这个异常一定会被抛出，抛出的异常自定义，可以不是真正产生的异常
            } else {
                System.out.println(s2);
            }
        } finally {
            System.out.println("throw异常处理结束");
        }
    }
}

class Exception3 {
    void Test3() throws ArithmeticException {//throws,写在方法名称后，throws后面跟可能抛出异常类型
        try {
            int a = 10 / 0;
        } finally {
            System.out.println("throws异常处理结束");
        }
    }
}